import { _decorator, Component, Node, Vec3 } from 'cc';
const { ccclass, property } = _decorator;

@ccclass('GameUtil')
export class GameUtil extends Component {
    public static formatNumber(num: number): string {
        num = Math.floor(num);
        if (Math.abs(num) >= 1e15) {
            return `999T`;
        } else if (Math.abs(num) >= 1e12) {
            const value = num / 1e12;
            return value >= 100 ? `${value.toFixed(0)}T` : value >= 10 ? `${value.toFixed(1)}T` : `${value.toFixed(2)}T`;
        } else if (Math.abs(num) >= 1e9) {
            const value = num / 1e9;
            return value >= 100 ? `${value.toFixed(0)}B` : value >= 10 ? `${value.toFixed(1)}B` : `${value.toFixed(2)}B`;
        } else if (Math.abs(num) >= 1e6) {
            const value = num / 1e6;
            return value >= 100 ? `${value.toFixed(0)}M` : value >= 10 ? `${value.toFixed(1)}M` : `${value.toFixed(2)}M`;
        } else if (Math.abs(num) >= 1e3) {
            const value = num / 1e3;
            return value >= 100 ? `${value.toFixed(0)}K` : value >= 10 ? `${value.toFixed(1)}K` : `${value.toFixed(2)}K`;
        } else {
            return num.toString();
        }
    }

    public static getBetween(num: number, min: number, max: number): number {
        if (num >= max) {
            return max;
        } else if (num <= min) {
            return min;
        } else {
            return num;
        }
    }

    /** 
     * 获取时间戳到现在时间的秒
    */
    public static getSecondByTimestamp(preTimestamp) {
        let nowDate = new Date();
        return Math.floor((nowDate.getTime() - preTimestamp) / 1000);
    }

    /**
     * 
     * @param startNode 
     * @param endNode 
     * @returns 获取两个节点之间的距离
     */
    public static getDistanceByNode(startNode: Node, endNode: Node) {
        return Vec3.distance(startNode.getWorldPosition(), endNode.getWorldPosition());
        // return startNode.getWorldPosition().clone().subtract(endNode.getWorldPosition().clone()).length();
    }

    /**
     *  获取枚举的临近属性 --- 可以从最后一个到第一个 
     * @param enumObject 
     * @param current 
     * @param next true向后 false向前
     * @param isBack 是否回溯
     * @returns 
     */
    public static getAdjacentEnumCirculation<T>(
        enumObject: T,
        current: T[keyof T],
        next: boolean = true,
        isBack: boolean = true
    ): T[keyof T] {
        const enumKeys = Object.keys(enumObject).filter(k => isNaN(Number(k)));
        const currentKey = enumKeys.find(k => enumObject[k] === current);

        if (!currentKey) {
            throw new Error('Current value not found in enum');
        }

        const index = enumKeys.indexOf(currentKey);
        const adjacentIndex = (index + (next ? 1 : -1) + enumKeys.length) % enumKeys.length;
        const adjacentKey = enumKeys[adjacentIndex];

        return enumObject[adjacentKey] as T[keyof T];
    }


    /** 获取数组的临近属性 */
    public static getAdjacentElement<T>(
        arr: T[],
        current: T,
        next: boolean = true
    ): T | undefined {
        const index = arr.indexOf(current);
        if (index === -1) {
            console.error('Current element not found in array');
            return undefined;
        }

        const adjacentIndex = index + (next ? 1 : -1);

        if (adjacentIndex >= 0 && adjacentIndex < arr.length) {
            return arr[adjacentIndex];
        }
        return undefined;
    }

    /**
 * 检查两个数组是否完全相同（包括元素顺序）
 * @param arr1 第一个数组
 * @param arr2 第二个数组
 * @returns boolean 两个数组是否完全相同
 */
    public static areArraysEqual<T>(arr1: T[], arr2: T[]): boolean {
        // 首先检查长度是否相同
        if (arr1.length !== arr2.length) {
            return false;
        }

        // 逐个比较每个元素
        return arr1.every((element, index) => {
            // 如果元素是对象或数组，需要进行深度比较
            if (typeof element === 'object' && element !== null) {
                return JSON.stringify(element) === JSON.stringify(arr2[index]);
            }
            return element === arr2[index];
        });
    }

    /**
     * 检查两个数组是否包含相同的元素（不考虑顺序）
     * @param arr1 第一个数组
     * @param arr2 第二个数组
     * @returns boolean 两个数组是否包含相同的元素
     */
    public static haveSameElements<T>(arr1: T[], arr2: T[]): boolean {
        // 首先检查长度是否相同
        if (arr1.length !== arr2.length) {
            return false;
        }

        // 对于基本类型数组，可以先排序再比较
        const sortedArr1 = [...arr1].sort();
        const sortedArr2 = [...arr2].sort();

        return sortedArr1.every((element, index) => {
            if (typeof element === 'object' && element !== null) {
                return JSON.stringify(element) === JSON.stringify(sortedArr2[index]);
            }
            return element === sortedArr2[index];
        });
    }

    /**
     * 
     * @param arr 
     * @returns 深度拷贝数组
     */
    public static deepCloneArray<T>(arr: T[]): T[] {
        // 深拷贝函数
        function deepClone<T>(item: T): T {
            // 如果是null或非对象类型，直接返回
            if (item === null || typeof item !== 'object') {
                return item;
            }

            // 处理数组
            if (Array.isArray(item)) {
                return item.map(deepClone) as T;
            }

            // 处理对象
            const clonedObj = {} as T;
            for (const key in item) {
                clonedObj[key] = deepClone(item[key]);
            }

            return clonedObj;
        }

        // 对数组进行深拷贝
        return arr.map(deepClone);
    }


    /*** 将数组内容进行随机排列 */
    public static RandArr<T>(arr: T[]): T[] {
        let arrClone = this.deepCloneArray(arr);
        // 首先从最大的数开始遍历，之后递减
        for (let i: number = arrClone.length - 1; i >= 0; i--) {
            // 随机索引值randomIndex是从0-arrClone.length中随机抽取的
            const randomIndex: number = Math.floor(Math.random() * (i + 1));
            // 下面三句相当于把从数组中随机抽取到的值与当前遍历的值互换位置
            const itemIndex = arrClone[randomIndex];
            arrClone[randomIndex] = arrClone[i];
            arrClone[i] = itemIndex;
        }
        // 每一次的遍历都相当于把从数组中随机抽取（不重复）的一个元素放到数组的最后面（索引顺序为：len-1,len-2,len-3......0）
        return arrClone;
    }

    /*** 打乱节点顺序 */
    public static shuffleArray<T>(array: T[]): T[] {
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];  // 交换元素
        }
        return array;
    }

    /**
     * 
     * @param arr 
     * @param i 
     * @param condition 
     * @returns 从数组 arr 的第 i 个元素开始，到数组末尾，然后从数组开头到第 i-1 个元素，查找满足某个条件的第一个元素，并返回它的下标：
     */
    public static findFirstIndexInCircularArray<T>(
        arr: T[],
        i: number,
        condition: (value: T) => boolean
    ): number {
        const n = arr.length;
        if (i < 0 || i >= n) {
            throw new Error("起始索引超出范围");
        }

        // 形成从第i个到末尾，再从头到i-1的循环数组索引
        const circularIndices = [...Array(n).keys()].slice(i).concat([...Array(n).keys()].slice(0, i));

        // 查找第一个满足条件的元素的下标
        for (const index of circularIndices) {
            if (condition(arr[index])) {
                return index;
            }
        }
        return -1; // 如果没有找到满足条件的元素
    }

}


